﻿#include "kutils.h"
#ifdef QT_DEBUG
#include <QDebug>
#endif
#include <QtMath>

float KUtils::round(float v, int dot_num)
{
    float xx = qPow(10.0f,dot_num);
    return ((float)qRound64(v*xx))/xx;
}
double KUtils::round(double v, int dot_num)
{
    double xx = qPow(10.0,dot_num);
    return ((double)qRound64(v*xx))/xx;
}
QString KUtils::human(float v,int dot_num)
{
    float abs_v = qAbs(v);
	if (abs_v < 100000.00)
		return QString::number(v, 'f', dot_num);

	// 亿万只保留一位小数
	if (dot_num > 1)
		dot_num = 1;
    if (abs_v >= 100000000.0)
		return QString::number(v/ 100000000.0, 'f', dot_num) + QStringLiteral("亿");

	return QString::number(v / 10000.0, 'f', dot_num) + QStringLiteral("万");
}

QString KUtils::human(double v, int dot_num)
{
	double abs_v = qAbs(v);

	long long midv = pow(10, 7 - dot_num);

	if (abs_v < midv)
		return QString::number(v, 'f', dot_num);

	// 亿万只保留一位小数
	//if (dot_num > 1)
		dot_num = 1;
	if (abs_v >= 100000000.0)
		return QString::number(v / 100000000.0, 'f', dot_num) + QStringLiteral("亿");

	return QString::number(v / 10000.0, 'f', dot_num) + QStringLiteral("万");
}

//QString KUtils::human(double v, int dot_num)
//{
//	double abs_v = qAbs(v);
//
//	if (abs_v < 100000.00)
//		return QString::number(v, 'f', dot_num);
//
//	// 亿万只保留一位小数
//	if (dot_num > 1)
//		dot_num = 1;
//	if (abs_v >= 100000000.0)
//		return QString::number(v / 100000000.0, 'f', dot_num) + QStringLiteral("亿");
//
//	return QString::number(v / 10000.0, 'f', dot_num) + QStringLiteral("万");
//}

// 点到直线的距离的平方
qreal KUtils::distance2(const QPointF& pt, const QPointF& p1, const QPointF&p2)
{
	//qreal a = (pt.x() - p1.x())*(p2.y() - p1.y());//分子的左半部分
	//qreal b = (pt.y() - p1.y())*(p1.x() - p2.x());//分子的右半部分
	//qreal c = a + b;//二者相加
	//c *= c;//平方(pow(c,2)貌似在这里更加麻烦)
	//a = pow(p2.y() - p1.y(), 2);//分母左半部分
	//b = pow(p1.x() - p2.x(), 2);//分母右半部分
	//c /= (a + b);//分子分母相除
	//return  c;// sqrt(c);//开方
	qreal a = p2.y() - p1.y();
	qreal b = p1.x() - p2.x();
	qreal c = p2.x() * p1.y() - p1.x() * p2.y();
	qreal d = (a * pt.x() + b * pt.y() + c);
	qreal e = a * a + b * b;
	if (e < 1e-13) // 两点重合
		return (pt.x() - p1.x()) * (pt.x() - p1.x()) + (pt.y() - p1.y()) * (pt.y() - p1.y());

	return (d * d) / (a * a + b * b);
}

// 点到直线的距离的平方
qreal KUtils::distance2(const QPointF& pt, const QLineF& line)
{
	return distance2(pt, line.p1(), line.p2());
}
// 点到直线的距离
qreal KUtils::distance(const QPointF& pt, const QLineF& line)
{
	qreal v = distance2(pt, line.p1(), line.p2());
	return sqrt(v);
}
// 点到点的距离的平方
qreal KUtils::distance2(const QPointF& pt, const QPointF& p1)
{
	return pow(pt.y() - p1.y(), 2) + pow(p1.x() - pt.x(), 2);//分母右半部分
}
// 点到点的距离
qreal KUtils::distance(const QPointF& pt, const QPointF& p1)
{
	qreal v = distance2(pt, p1);
	return sqrt(v);
}



/**
 * 直线上取一点
 */
void KUtils::getLinePoint(const QPointF&p1, const QPointF&p2, qreal _x, QPointF&out)
{
	qreal y = 0, x = 0;
	qreal sig = ((p1.x() < p2.x()) ? 1 : 0);
	if (p1.x() == p2.x()) {
		x = p1.x();
		y = ((p1.y() < p2.y()) ? 1 : 0) * 10000;
	}
	else {
		qreal d = (p1.y() - p2.y()) / (p1.x() - p2.x());
		x = _x * sig;
		y = p1.y() - d * (p1.x() - _x * sig);

	}
	out.setX(x);
	out.setY(y);
}
/**
 * 计算垂足
 */
void KUtils::calcFootPoint(const QPointF&pt1, const QPointF&pt2, const QPointF&point, QPointF&out)
{
	if (pt1.x() == pt2.x()) {
		out.setX(pt1.x());
		out.setY(point.y());
	}
	else if (pt1.y() == pt2.y()) {
		out.setY(pt1.y());
		out.setX(point.x());
	}
	else {
		float k = (pt2.y() - pt1.y()) / (pt2.x() - pt1.x());
		float x = (pow(k, 2) * pt1.x() + k * (point.y() - pt1.y()) + point.x()) / (pow(k, 2) + 1);
		float y = k * (x - pt1.x()) + pt1.y();
		out.setX(x);
		out.setY(y);
	}
}
/**
 * 判断垂点在线段上的位置， pt1(a)------------------pt2(b)
 * 返回值：0=在线段上，-1=在pt2~pt1延长线上，1=在pt1~pt2延长线上
 */
int KUtils::testFootPoint(const QPointF&a, const QPointF&b, const QPointF&p)
{
	QPointF ab = QPointF(b.x() - a.x(), b.y() - a.y());
	QPointF ap = QPointF(p.x() - a.x(), p.y() - a.y());
	qreal f = ab.x()*ap.x() + ab.y()*ap.y();
	//angle between 90 and 270
	if (f < 0)
		return -1;
	qreal d = ab.x()*ab.x() + ab.y()*ab.y();
	if (f > d)
		return 1;
	return 0;
	/* ========================================= */
	//float v = (pt2.x() - pt1.x())*(pt2.x() - pt1.x()) + (pt2.y() - pt1.y())*(pt2.y() - pt1.y());
	//float v_f1 = (foot.x() - pt1.x())*(foot.x() - pt1.x()) + (foot.y() - pt1.y())*(foot.y() - pt1.y());
	//float v_f2 = (foot.x() - pt2.x())*(foot.x() - pt2.x()) + (foot.y() - pt2.y())*(foot.y() - pt2.y());
	//if (v_f2 <= v && v_f1 <= v)
	//	return 0;
	//return (v_f1 < v_f2) ? -1 : 1;
}
//bool KUtils::calcRange(QVector<VALUE_TYPE>*data, int idx, int in_count, VALUE_TYPE&out_max_value, VALUE_TYPE&out_min_value)
//{
//	if (idx < 0)
//		return false;
//	int count = idx + in_count;
//	int nc = qMin(count, data->count()) - idx;
//	if (nc <= 0)
//		return false;
//
//	int null_count = 0;
//	for (int i = 0; i < nc; i++) {
//		if (!IS_VALUE_NULL(data->operator[](idx + i)))
//			break;
//		null_count++;
//	}
//	if (null_count == nc)
//		return false;
//
//	// 计算最大值/最小值
//	VALUE_TYPE max_value = (data->operator[](idx+null_count));
//	VALUE_TYPE min_value = max_value;// 999999999.00f;
//	for (int i = null_count; i < nc; i++)
//	{
//		VALUE_TYPE v = (data->operator[](idx + i));
//		max_value = qMax<VALUE_TYPE>(max_value, v);
//		min_value = qMin<VALUE_TYPE>(min_value, v);
//	}
//	out_max_value = max_value;
//	out_min_value = min_value;
//
//	return true;
//}
float KUtils::gradient(const QPointF&p0, const QPointF&p1)
{
	return (p1.y() - p0.y()) / (p1.x() - p0.x());
}


qreal KUtils::pt2LineSegmentDistance(const QPointF&p, const QPointF& a, const QPointF&b)
{
	QPointF ret_pos;

	QPointF ab = QPointF(b.x() - a.x(), b.y() - a.y());
	QPointF ap = QPointF(p.x() - a.x(), p.y() - a.y());
	qreal f = ab.x()*ap.x() + ab.y()*ap.y();
	//angle between 90 and 270
	if (f < 0) {
		ret_pos = a;
		return distance(a, p);
	}
	qreal d = ab.x()*ab.x() + ab.y()*ab.y();
	if (f > d) {
		ret_pos = b;
		return distance(b, p);
	}
	f /= d;
	QPointF m = QPointF(a.x() + f * ab.x(), a.y() + f * ab.y());
	ret_pos = m;
	return distance(m, p);
}
qreal KUtils::pt2LineDistance(const QPointF&p, const QPointF& a, const QPointF&b)
{
	QPointF ab = QPointF(b.x() - a.x(), b.y() - a.y());
	QPointF ap = QPointF(p.x() - a.x(), p.y() - a.y());
	qreal f = qAbs(ab.x()*ap.y() - ab.y()*ap.x());
	qreal d = sqrt(ab.x()*ab.x() + ab.y()*ab.y());
	return f / d;
}
qreal KUtils::pt2LineDistance(const QPointF&p, const QPointF& a, const QPointF&b, bool is_segment)
{
	if (is_segment)
		return pt2LineSegmentDistance(p, a, b);
	return pt2LineDistance(p, a, b);
}
bool KUtils::testIntersectPos(QLineF A, QLineF B, QPointF*out)//返回A与B交点，无交点返回（0,0）
{
	QLineF::IntersectType type = A.intersect(B, out);
	return (type == QLineF::BoundedIntersection);
}
bool KUtils::testIntersectPos(QPointF posA, QPointF posB, QPointF posC, QPointF posD, QPointF*out)//返回AB与CD交点，无交点返回（0,0）
{
	QLineF line1(posA, posB);
	QLineF line2(posC, posD);
	QLineF::IntersectType type = line1.intersect(line2, out);
	return (type == QLineF::BoundedIntersection);
}
double KUtils::minPrecision(int dot_digits)
{
	double r = 1.0;
	while (dot_digits--) {
		r /= 10;
	}
	return r;
}
double KUtils::base(double f)
{
	if (!f)
		return 0;

	double x = 1;
	if (qAbs(f) < 1) {
		while ((qAbs(f) / x) < 1) {
			x /= 10;
		}
		return x;// f > 0 ? 0.1 : -0.1;
	}

	qint64 v = f;
	while (v >= 10) {
		v /= 10;
		x *= 10;
	}
	return x;
}
double KUtils::floor(double v, double significance)
{
	int x = 1;
	double d = significance;
	while (d - (qint64)d > 0) {
		x *= 10;
		d *= 10;
	}
	return ((qint64)::floor((v / d)) * (qint64)d) / x;
}

double KUtils::ceil(double v, double significance)
{
	int x = 1;
	double d = significance;
	while (d - (qint64)d > 0) {
		x *= 10;
		d *= 10;
	}
	return ((qint64)::ceil((v / d)) * (qint64)d) / x;
}

/*1、取反转颜色*/

QColor KUtils::invertColor(const QColor &crColor)
{
	QColor crInvert;
	crInvert.setRgb(255 - crColor.red(), 255 - crColor.green(), 255 - crColor.blue());
	return crInvert;
}



/*2、颜色异或^*/

QColor KUtils::changeXORColor(QColor crColor, QColor crBkColor)
{
	QColor crInvert;
	crInvert = (crColor.value() ^ crBkColor.value());
	return crInvert;
}

QDate KUtils::kdateOf(const QString&d)
{
	return QDate(d.left(4).toInt(), d.mid(4, 2).toInt(), d.right(2).toInt());
}
QTime KUtils::ktimeOf(const QString&t)
{
	return QTime(t.left(2).toInt(), t.mid(3, 2).toInt(), t.right(2).toInt());
}
QDateTime KUtils::kdatetimeOf(const QString&d, const QString&t)
{
	return QDateTime(kdateOf(d), ktimeOf(t));
}
int KUtils::kdayOf(const QString&d1, const QString&d2)
{
	return kdateOf(d1).daysTo(kdateOf(d2));
}
